package lol.clann.minecraft.springboot.plugin.core.service;

import lol.clann.minecraft.springboot.api.context.PluginContext;
import lol.clann.minecraft.springboot.api.model.core.Plugin;
import lol.clann.minecraft.springboot.plugin.core.database.datasource.DataSourceConfig;
import lol.clann.minecraft.springboot.api.spi.ddl.DDL;
import lol.clann.minecraft.springboot.plugin.core.mapper.DDLMapper;
import lol.clann.minecraft.springboot.plugin.core.model.DDLVersion;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ClassUtils;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.*;

/**
 * 这个手动创建
 *
 * @author pyz
 * @date 2019/8/1 11:10 PM
 */
@Slf4j
@Component
@DependsOn("sqlSessionFactory")
@ConditionalOnProperty(name = "springbootplugin.datasource.enable", havingValue = "true")
public class DDLExecutor {

    @Autowired
    private DataSourceConfig config;
    @Autowired
    private DDLMapper mapper;
    @Autowired
    private List<DDL> ddlSqls;
    private Map<String, List<DDL>> ddlMap = new HashMap<>();

    @PostConstruct
    private void postConstruct() throws IOException {
//        处理所有的 DDLExecutor
        for (DDL ddl : this.ddlSqls) {
            Plugin plugin = PluginContext.getPluginByClass(ClassUtils.getUserClass(ddl.getClass()));
            if (plugin == null) {
                throw new Error(String.format("找不到类 %s 所属的插件", ClassUtils.getUserClass(ddl.getClass()).getName()));
            }
            ddlMap.computeIfAbsent(plugin.getId(), k -> new ArrayList<>()).add(ddl);
        }
        for (List<DDL> value : ddlMap.values()) {
            value.sort(Comparator.comparingInt(DDL::getVersion));
        }
    }


    @Transactional(rollbackFor = Throwable.class)
    public void initSbpPlugin() {
        LOGGER.info("创建sbp表结构...");
        Plugin plugin = PluginContext.getSBPPlugin();
        List<DDL> ddls = ddlMap.get(plugin.getId());
        DDLVersion version = new DDLVersion();
        version.setPlugin(plugin.getId());
        for (DDL ddl : ddls) {
            for (String sql : ddl.getSqls()) {
                LOGGER.info("execute ddl. plugin={}. sql={}", plugin.getId(), sql);
                mapper.execute(sql);
            }
            version.setVersion(ddl.getVersion());
        }
        LOGGER.info("insertDDlVersion: "+ version.toString());
        mapper.insertDDlVersion(version);
        LOGGER.info("sbp表结构创建完毕...");
    }


    @Transactional(rollbackFor = Throwable.class)
    public DDLVersion executeDDL(DDLVersion version, DDL ddl) {
        if (version.getVersion() >= ddl.getVersion()) {
            return version; // 已经执行过的
        }
        List<String> sqls = ddl.getSqls();
        if (sqls != null && !sqls.isEmpty()) {
            for (String sql : sqls) {
                LOGGER.info("execute ddl. plugin={}. sql={}", version.getPlugin(), sql);
                mapper.execute(sql);
            }
        }
        version.setVersion(ddl.getVersion());
        if (version.getId() == 0) {
            mapper.insertDDlVersion(version);
        } else {
            mapper.updateDDlVersion(version);
        }
        return version;
    }

    public Map<String, List<DDL>> getDdlMap() {
        return ddlMap;
    }
}
